//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<layer.h>
///	@path	~/src/gui/composite/
///	@date	2008/05/22
///	@desc	.

#pragma once

#include "xeres.h"

// !Notice: Currently we might use GDI+ as layer renderer.

#ifndef _FULLAPI
#error Compiling with GDI+ must specify _FULLAPI before <config.h>.
#endif /*_FULLAPI*/

#include <GdiPlus.h>

#include "lib/math/color.h"
#include "lib/math/rect.h"
#include "lib/math/math_win32.h"

#include "gui/style/style.h"
#include "gui/image/IBitmap.h"

using Gdiplus::Graphics;

namespace xeres {

	// forward declaration
	class Composition;

	/*! 
		\class	Layer
		\brief	Holds a rendering buffer that associates an HDC.
	*/
	class Layer
	{
	public:

		/// \ctor
		Layer( void );

		/// \dtor
		~Layer( void );

		/// \name		Layer Manipulation
		//@{

		///	\brief		Resize layer.
		void Resize( size_t width , size_t height );

		///	\brief		Get the width of layer.
		uint GetWidth( void ) const { return m_width; }

		///	\brief		Get the height of layer.
		uint GetHeight( void ) const { return m_height; }

		///	\brief		Get image total size in byte.
		size_t GetImageSize( void ) const { return m_bmi.bmiHeader.biSizeImage; }

		///	\brief		Get device context of layer.
		HDC GetDC( void ) const { return m_hdc; }

		/// \brief		Get bitmap info.
		const BITMAPINFO * GetBitmapInfo( void ) const { return &m_bmi; }

		/// \brief		Get bitmap object.
		Gdiplus::Bitmap * GetBitmap( void ) {
			return (Gdiplus::Bitmap*)m_BitmapBuffer;
		}

		///	\brief		Get pixel by coordinate (invert).
		ARGB * GetPixelInvert( int x , int y ) {
			assert( x >= 0 && x < (int)m_width && y >= 0 && y < (int)m_height );
			return m_bits + ( ( m_height - y - 1 ) * m_width + x );
		}

		///	\brief		Get pixel by coordinate (invert).
		const ARGB * GetPixelInvert( int x , int y ) const {
			assert( x >= 0 && x < (int)m_width && y >= 0 && y < (int)m_height );
			return m_bits + ( ( m_height - y - 1 ) * m_width + x );
		}

		///	\brief		Get pixel by coordinate.
		ARGB * GetPixel( int x , int y ) {
			assert( x >= 0 && x < (int)m_width && y >= 0 && y < (int)m_height );
			return m_bits + ( y * m_width + x );
		}

		///	\brief		Get pixel by coordinate.
		const ARGB * GetPixel( int x , int y ) const {
			assert( x >= 0 && x < (int)m_width && y >= 0 && y < (int)m_height );
			return m_bits + ( y * m_width + x );
		}

		///	\brief		Get pixel with specific line width.
		ARGB * GetPixelInvert( int x , int y , int linewidth ) {
			assert( x >= 0 && x < (int)m_width && y >= 0 && y < (int)m_height );
			assert( linewidth == ( ( (int)m_height - y - 1 ) * (int)m_width ) );
			return m_bits + linewidth + x;
		}

		///	\brief		Get pixel with specific line width.
		const ARGB * GetPixelInvert( int x , int y , int linewidth ) const {
			assert( x >= 0 && x < (int)m_width && y >= 0 && y < (int)m_height );
			assert( linewidth == ( ( (int)m_height - y - 1 ) * (int)m_width ) );
			return m_bits + linewidth + x;
		}

		///	\brief		Clear specific rectangle.
		void Clear( int left , int top , int width , int height );

		///	\brief		Clear layer.
		void Clear( void );

		///	\brief		Fill specific rectangle.
		void Fill( const PackColor4& col ,int left , int top , int width , int height );

		/// \brief		Composite source layer to this layer.
		void Composite( const Pair<int>& start , const Rect<int>& bound , Layer * src , const Rect<int>& region , int alpha );

		/// \brief		Composite bitmap to this layer.
		void Composite( const Pair<int>& start , const Rect<int>& bound , RefWeak<IBitmap> bitmap , const Rect<int>& region , int alpha , int frame );

		/// \brief		Blending frame & composite.
		void BlendFrame( const Pair<int>& start , const Rect<int>& bound , RefWeak<IBitmap> bitmap , const Rect<int>& region , int alpha , int frame1 , int frame2 , float blending );

		///	\brief		
		void DrawText( const ARGB& ctext , HFONT fnt , const wchar_t * text , int len , const RECT& rc , const RECT& bound , UINT format );
	
		///	\brief
		void DrawShadowText( const ARGB& ctext , const ARGB& cshadow , HFONT fnt , const wchar_t * text , int len ,
			const RECT& rc , const RECT& bound , UINT format , int cx , int cy );

		/// \brief
		void DrawText( const ARGB& ctext , RefWeak<StyleFont> font , const wchar_t * text , int len , const RECT& rc , const RECT& bound );

		/// \brief
		void DrawText( const ARGB& ctext , RefWeak<StyleFont> font , const wchar_t * text , int len , const RECT& bound , const Pair<int>& pos ,
			int * arrangement , TextStyle * style , wchar_t prev );

		// GetTextWidth
		RECT GetTextWidth( HFONT fnt , const wchar_t * text , int len , UINT format , bool shadowed , int cx = 0 , int cy = 0 );

		/// \brief		Blur specific area of layer.
		void Blur( const Rect<int>& rect , int radius );

		/// \brief		Down sample.
		void DownSample( const Rect<int>& region , int radius );

		//@}

	private:

		//@ data

		HDC				m_hdc;
		HBITMAP			m_hBmp;
		HBITMAP			m_hOldBmp;
		UINT			m_width;
		UINT			m_height;
		ARGB *			m_bits;
		BITMAPINFO		m_bmi;
		byte			m_BitmapBuffer[ ALIGNOF( sizeof(Gdiplus::Bitmap) / sizeof(byte) , 16 ) ];
	};

} // namespace xeres
